<?php
require_once 'FShell/ShellException.php';

abstract class BaseShell {
	protected $timeLimit = 0;
	protected $memoryLimit = 0;
	protected $processNumberLimit = 1;
	
	public function __construct($timeLimit = null, $memoryLimit = null, $processNumberLimit = null) {
		$this->setTimeLimit($timeLimit)
			->setMemoryLimit($memoryLimit)
			->setProcessNumberLimit($processNumberLimit);
	}
	
	public function println($message = '') {
		echo $message . "\r\n";
	}
	
	public function setTimeLimit($timeLimit = null) {
		if (null === $timeLimit) return $this;
		if ($timeLimit < 0) throw new ShellException('timeLimit should >= 0');
		$this->timeLimit = $timeLimit;
		
		return $this;
	}
	
	public function setMemoryLimit($memoryLimit = null) {
		if (null === $memoryLimit) return $this;
		if ($memoryLimit < 0) throw new ShellException('memoryLimit should >= 0');
		$this->memoryLimit = $memoryLimit;
		
		return $this;
	}
	
	public function setProcessNumberLimit($processNumberLimit = null) {
		if (null === $processNumberLimit) return $this;
		if ($processNumberLimit < 0) throw new ShellException('processNumberLimit should >= 0');
		$this->processNumberLimit = $processNumberLimit;
		
		return $this;
	}
	
	public function execute() {
		$this->beforeRun();
		$this->run();
		$this->afterRun();
	}
	
	protected function beforeRun() {
		$this->applyTimeLimit()
			->applyMemoryLimit()
			->applyProcessNumberLimit();
	}
	
	abstract protected function run();
	
	protected function afterRun() {
	}

	
	protected function applyTimeLimit($timeLimit = null) {
		$this->setTimeLimit($timeLimit);
		set_time_limit($this->timeLimit);
		
		return $this;
	}
	
	protected function applyMemoryLimit($memoryLimit = null) {
		$this->setMemoryLimit($memoryLimit);
		$this->memoryLimit && ini_set('memory_limit', $this->memoryLimit);
		
		return $this;
	}
	
	protected function applyProcessNumberLimit($processNumberLimit = null) {
		$this->setProcessNumberLimit($processNumberLimit);
		if ($this->processNumberLimit) {
			require_once 'FShell/process.class.php';
			PROCESS::limit(isset($_SERVER['argv']) ? $_SERVER['argv'] : array(), $this->processNumberLimit, false);
		}
		
		return $this;
	}
}

